#include <stdio.h>
#include <regex.h>
#include <assert.h>

/** REGEX:匹配条目头,catalog,type 字段 */
const static char* _RX_ITEM_TYPER = "^(M|C|O[a-f0-9]{1,2})";
/** REGEX:匹配条目所有 bool 类型字段 */
const static char* _RX_ITEM_FLAGS = "^F[0-9]{1,4}";
/** REGEX:匹配条目 name 字段 */
const static char* _RX_ITEM_NAME = "^N\"[a-zA-Z0-9_]+\"";
/** REGEX:匹配条目 uiName 字段 */
const static char* _RX_ITEM_UINAME = "^U\"([^\"\\\\]|\\\\.)+\"";
/** REGEX:匹配条目 description 字段 */
const static char* _RX_ITEM_DESC = "^D\"([^\"\\\\]|\\\\.)+\"";
/** REGEX:匹配条目 path 字段 */
const static char* _RX_ITEM_PATH = "^P\"([^\"]+)\"";

/** REGEX:匹配OPTION value 字段 */
const static char* _RX_OPT_VALUE = "^v\"([^\"\\\\]|\\\\.)+\"";
/** REGEX:匹配OPTION defaultValue 字段 */
const static char* _RX_OPT_DEFVALUE = "^d\"([^\"\\\\]|\\\\.)+\"";
/** REGEX:匹配OPTION regex 字段 */
const static char* _RX_OPT_REGEX = "^r\"([^\"\\\\]|\\\\.)+\"";
/** REGEX:匹配OPTION fieldRequire 字段 */
const static char* _RX_OPT_FIELDREQ = "^f\"[0-9]\"";
/** REGEX:匹配OPTION precision 字段 */
const static char* _RX_OPT_PRECISION = "^p\"[0-9]\"";
/** REGEX:匹配OPTION width 字段 */
const static char* _RX_OPT_WIDTH = "^w\"[0-9]+\"";
/** REGEX:匹配OPTION height 字段 */
const static char* _RX_OPT_HEIGHT = "^h\"[0-9]+\"";
/** REGEX:匹配OPTION suffix 字段 */
const static char* _RX_OPT_SUFFIX = "^s\"([^\"\\\\]|\\\\.)+\"";
/** REGEX:匹配OPTION available 字段 */
const static char* _RX_OPT_AVAILABLE = "^a\"([^\"\\\\]|\\\\.)+\"";
/** REGEX:匹配OPTION options 字段 */
const static char* _RX_OPT_OPTIONS = "^o\"([^\"\\\\]|\\\\.)+\"";


/** regex 错误输出缓冲区 */
static char regerrbuf[256];
//************************************
// 编译正则表达式
// @param    regex_t * reg
// @param    const char * pattern 正则表达式
// @return   int 编译成功返回 0,否则返回DJC_REGEX_PATTERN_ERR
//************************************
static int make_pattern(regex_t *reg, const char*pattern)
{
	int c = regcomp(reg, pattern, REG_EXTENDED);
	if (0 != c)
	{
		regerror(c, reg, regerrbuf, sizeof(regerrbuf));
		regerrbuf[sizeof(regerrbuf) - 1] = '\0';
		printf("%s", regerrbuf);
		return -1;
	}
	return 0;
}

//************************************
// 用指定的正则表达式在字符串中匹配
// @param    const char * cjs 待匹配的字符串
// @param    const char * pattern 正则表达式
// @return   int 匹配成功返回匹配结束偏移量,没有匹配返回0,正则表达式执行错误返回错误代码 DJC_REGEX_MATCH_ERR
//************************************
int match_field(const char*cjs, const char*pattern)
{
	regex_t reg;
	int c = make_pattern(&reg, pattern);
	assert(0 == c);
	regmatch_t pmatch;   /** 定义匹配结果在待匹配串中的下标范围 */
	c = regexec(&reg, cjs, 1, &pmatch, 0); /** 匹配他 */
	regfree(&reg);
	switch (c)
	{
	case REG_NOMATCH:
		return -1;
	case 0:
		break;
	default:
	{
		regerror(c, &reg, regerrbuf, sizeof(regerrbuf));
		regerrbuf[sizeof(regerrbuf) - 1] = '\0';
		printf("%s", regerrbuf);
		return -1;
	}
	}
	for (int i = pmatch.rm_so; i < pmatch.rm_eo; i++) 
	{
		printf("%c", cjs[i]);
	}
	printf("\n");
	return pmatch.rm_eo;
}

int test(const char*input, const char*pattern)
{
	int c = match_field(input, pattern);
	if (c <= 0)
	{
		printf("MIST MATCH %s FOR %s\n", pattern, input);
		return 1;
	}
	return 0;
}

int main()
{
	int errcout = 0;
	errcout += test("M", _RX_ITEM_TYPER);
	errcout += test("C", _RX_ITEM_TYPER);
	errcout += test("Of", _RX_ITEM_TYPER);
	errcout += test("F50", _RX_ITEM_FLAGS);
	errcout += test("F01", _RX_ITEM_FLAGS);
	errcout += test("N\"reset\"", _RX_ITEM_NAME);
	errcout += test("N\"quit\"", _RX_ITEM_NAME);
	errcout += test("U\"\\\"恢复出厂\\\"\"", _RX_ITEM_UINAME);
	errcout += test("D\"\\\"恢复出厂\\\"\"", _RX_ITEM_DESC);
	errcout += test("P\"/menu1\"", _RX_ITEM_PATH);
	errcout += test("v\"\\\"123456789\\\"\"", _RX_OPT_VALUE);
	errcout += test("d\"\\\"123456789\\\"\"", _RX_OPT_DEFVALUE);
	errcout += test("r\"\\\"^\\\\\\\\s*\\\\\\\\d+\\\\\\\\s*$\\\"\"", _RX_OPT_REGEX);
	errcout += test("f\"7\"", _RX_OPT_FIELDREQ);
	errcout += test("p\"7\"", _RX_OPT_PRECISION);
	errcout += test("w\"7\"", _RX_OPT_WIDTH);
	errcout += test("h\"23\"", _RX_OPT_HEIGHT);
	errcout += test("s\"jpg\"", _RX_OPT_SUFFIX);
	//errcout += test("o\"{\\\"1\\\":\\\"1低\\\",\\\"2\\\":\\\"2中\\\",\\\"3\\\":\\\"3高\\\"}\"", _RX_OPT_OPTIONS);
	//errcout += test("a\"{\\\"1\\\":\\\"1低\\\",\\\"2\\\":\\\"2中\\\",\\\"3\\\":\\\"3高\\\"}\"", _RX_OPT_AVAILABLE);
	if (!errcout)
	{
		printf("ALL TEST PASS!\n");
		return 0;
	}
	return errcout;
}